package com.sb;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;

import net.neoremind.sshxcute.core.IOptionName;
import net.neoremind.sshxcute.core.SSHExec;
import au.com.bytecode.opencsv.CSVReader;

import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;

/**
 * 
 * @author sbrito
 * 
 */
public class FirewallRuleCheckUI
{

	private JFrame frmSshFirewallValidator;
	private JTextField authFileTextField;
	private JTextField rulesFileTextField;
	private static JProgressBar progressBar;
	private static JTextArea resultsTextArea;

	private static double progressBatIncrementPercent = 0;
	private static final int SSH_TIMEOUT = 15000;
	private static final int SSH_PORT = 22;
	public static final int SSH_COMMAND_CHANNEL_TIMEOUT = 15000;
	public static final long SSH_COMMAND_EXEC_TIMEOUT = 15000;
	public static final int SOCKET_READ_RETRY = 3;// some hosts may be slow
	private static double progressBarValue=0;
	private JTextField threadCountTextField;

	// only allow one thread to update this at a time.
	public static synchronized void incrementProgressBar()
	{
		progressBarValue=progressBarValue + progressBatIncrementPercent;
		progressBar.setValue((int)progressBarValue);
	}

	/**
	 * Launch the application.
	 */
	public static void main(String[] args)
	{
		SSHExec.setOption(IOptionName.HALT_ON_FAILURE, false);
		SSHExec.setOption(IOptionName.SSH_PORT_NUMBER, SSH_PORT);
		SSHExec.setOption(IOptionName.INTEVAL_TIME_BETWEEN_TASKS, 0);// ms
		SSHExec.setOption(IOptionName.TIMEOUT, SSH_TIMEOUT);// mstimeout

		EventQueue.invokeLater(new Runnable()
		{
			public void run()
			{
				try
				{
					FirewallRuleCheckUI window = new FirewallRuleCheckUI();
					window.frmSshFirewallValidator.setVisible(true);
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public FirewallRuleCheckUI()
	{
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize()
	{
		frmSshFirewallValidator = new JFrame();
		frmSshFirewallValidator.setResizable(false);
		frmSshFirewallValidator.setTitle(Messages.getString("FirewallRuleCheckUI.0")); 
		frmSshFirewallValidator.setBounds(100, 100, 800, 600);
		frmSshFirewallValidator.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frmSshFirewallValidator.getContentPane().setLayout(new BorderLayout(0, 0));

		resultsTextArea = new JTextArea(5, 20);
		JScrollPane scrollPane = new JScrollPane(resultsTextArea);
		resultsTextArea.setEditable(false);
		resultsTextArea.setLineWrap(true);

		frmSshFirewallValidator.getContentPane().add(scrollPane, BorderLayout.CENTER);

		progressBar = new JProgressBar();
		frmSshFirewallValidator.getContentPane().add(progressBar, BorderLayout.SOUTH);
		progressBar.setStringPainted(true);

		JPanel fileChooserPanel = new JPanel();
		frmSshFirewallValidator.getContentPane().add(fileChooserPanel, BorderLayout.NORTH);
		fileChooserPanel.setLayout(new BorderLayout(0, 0));

		JPanel authPanel = new JPanel();
		authPanel.setBackground(Color.LIGHT_GRAY);
		fileChooserPanel.add(authPanel, BorderLayout.NORTH);
		authPanel.setLayout(new FormLayout(new ColumnSpec[]
		{ ColumnSpec.decode("left:max(80dlu;min)"), FormFactory.LABEL_COMPONENT_GAP_COLSPEC, FormFactory.GROWING_BUTTON_COLSPEC, 
				FormFactory.LABEL_COMPONENT_GAP_COLSPEC, FormFactory.BUTTON_COLSPEC, }, new RowSpec[]
		{ RowSpec.decode("23px"), })); 

		JLabel label = new JLabel(Messages.getString("FirewallRuleCheckUI.3")); 
		label.setHorizontalAlignment(SwingConstants.LEFT);
		authPanel.add(label, "1, 1, left, default"); 

		rulesFileTextField = new JTextField(50);
		authPanel.add(rulesFileTextField, "3, 1, 2, 1, fill, fill"); 

		JButton csvFileChooserButton = new JButton(Messages.getString("FirewallRuleCheckUI.6")); 
		csvFileChooserButton.setHorizontalAlignment(SwingConstants.RIGHT);
		csvFileChooserButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(new File(System.getProperty(Messages.getString("FirewallRuleCheckUI.7")))); 
				FileNameExtensionFilter filter = new FileNameExtensionFilter(Messages.getString("FirewallRuleCheckUI.8"), Messages 
						.getString("FirewallRuleCheckUI.9")); 
				chooser.setFileFilter(filter);
				int returnVal = chooser.showOpenDialog(frmSshFirewallValidator);
				if (returnVal == JFileChooser.APPROVE_OPTION)
				{
					// System.out.println("You chose to open this file: " +
					// chooser.getSelectedFile().getAbsolutePath());
					rulesFileTextField.setText(chooser.getSelectedFile().getAbsolutePath());
				}
			}
		});
		authPanel.add(csvFileChooserButton, "5, 1, fill, fill"); 

		JPanel csvPanel = new JPanel();
		csvPanel.setBackground(Color.LIGHT_GRAY);
		fileChooserPanel.add(csvPanel, BorderLayout.CENTER);
		csvPanel.setLayout(new FormLayout(new ColumnSpec[]
		{ ColumnSpec.decode("left:max(80dlu;min)"), FormFactory.LABEL_COMPONENT_GAP_COLSPEC, FormFactory.GROWING_BUTTON_COLSPEC, 
				FormFactory.LABEL_COMPONENT_GAP_COLSPEC, FormFactory.BUTTON_COLSPEC, }, new RowSpec[]
		{ RowSpec.decode("23px"), })); 

		JLabel lblSelectFirewallRules = new JLabel(Messages.getString("FirewallRuleCheckUI.13")); 
		csvPanel.add(lblSelectFirewallRules, "1, 1, left, fill"); 

		authFileTextField = new JTextField(50);
		csvPanel.add(authFileTextField, "3, 1, 2, 1, fill, fill"); 

		JButton authFileChooseButton = new JButton(Messages.getString("FirewallRuleCheckUI.16")); 
		authFileChooseButton.setHorizontalAlignment(SwingConstants.RIGHT);
		authFileChooseButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{

				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); 
				FileNameExtensionFilter filter = new FileNameExtensionFilter(Messages.getString("FirewallRuleCheckUI.18"), Messages 
						.getString("FirewallRuleCheckUI.19")); 
				chooser.setFileFilter(filter);
				int returnVal = chooser.showOpenDialog(frmSshFirewallValidator);
				if (returnVal == JFileChooser.APPROVE_OPTION)
				{
					// System.out.println("You chose to open this file: " +
					// chooser.getSelectedFile().getAbsolutePath());
					authFileTextField.setText(chooser.getSelectedFile().getAbsolutePath());
				}

			}
		});
		csvPanel.add(authFileChooseButton, "5, 1, fill, fill"); 

		JPanel startButtonPanel = new JPanel();
		fileChooserPanel.add(startButtonPanel, BorderLayout.SOUTH);

		JButton btnStartRulesValidation = new JButton(Messages.getString("FirewallRuleCheckUI.21")); 
		btnStartRulesValidation.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				validateRules(rulesFileTextField.getText(), authFileTextField.getText());
			}

			private void validateRules(String rulesFile, String authFile)
			{
				resultsTextArea.setText(Messages.getString("FirewallRuleCheckUI.22")); 

				class swingWorker extends SwingWorker<Integer, Integer>
				{
					long startTime=0;
					long endTime=0;
					
					public swingWorker(String rulesFile, String authFile)
					{
						super();
						this.rulesFile = rulesFile;
						this.authFile = authFile;
					}

					String rulesFile;
					String authFile;

					protected Integer doInBackground() throws Exception
					{
						startTime=System.currentTimeMillis();
						// Do a time-consuming task.
						List<String[]> authList = null;
						List<String[]> firewallRuleList = null;

						File f = new File(rulesFile);
						if (!f.exists() || !f.canRead())
						{
							JOptionPane.showMessageDialog(frmSshFirewallValidator, Messages.getString("FirewallRuleCheckUI.23") + rulesFile, 
									Messages.getString("FirewallRuleCheckUI.24"), JOptionPane.ERROR_MESSAGE); 
							addMessageToStatus(Messages.getString("FirewallRuleCheckUI.25") + rulesFile); 
							return -1;
						}
						CSVReader reader1;
						try
						{
							reader1 = new CSVReader(new FileReader(f));
							firewallRuleList = reader1.readAll();
							reader1.close();
							addMessageToStatus(Messages.getString("FirewallRuleCheckUI.26") + (firewallRuleList.size() - 1) 
									+ Messages.getString("FirewallRuleCheckUI.27")); 

						}
						catch (FileNotFoundException e1)
						{
							e1.printStackTrace();
						}
						catch (IOException e)
						{
							e.printStackTrace();
						}
						f = new File(authFile);
						if (!f.exists() || !f.canRead())
						{
							JOptionPane.showMessageDialog(frmSshFirewallValidator, Messages.getString("FirewallRuleCheckUI.28") + authFile, 
									Messages.getString("FirewallRuleCheckUI.29"), JOptionPane.ERROR_MESSAGE); 
							addMessageToStatus(Messages.getString("FirewallRuleCheckUI.30") + authFile); 
							return -1;
						}
						CSVReader reader2;
						try
						{
							reader2 = new CSVReader(new FileReader(f));
							authList = reader2.readAll();
							reader2.close();
							addMessageToStatus(Messages.getString("FirewallRuleCheckUI.31") + (authList.size()) 
									+ Messages.getString("FirewallRuleCheckUI.32")); 
							if (authList.get(0).length != 2)
							{
								JOptionPane.showMessageDialog(frmSshFirewallValidator, Messages.getString("FirewallRuleCheckUI.33"), 
										Messages.getString("FirewallRuleCheckUI.34"), JOptionPane.ERROR_MESSAGE); 
								addMessageToStatus(Messages.getString("FirewallRuleCheckUI.35")); 
								return -1;
							}
						}
						catch (FileNotFoundException e)
						{
							e.printStackTrace();
						}
						catch (IOException e)
						{
							e.printStackTrace();
						}

						String username = authList.get(0)[0];
						String password = authList.get(0)[1];

						SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); 

						try
						{
							SSHExec.showEnvConfig();
						}
						catch (Exception e1)
						{
							e1.printStackTrace();
						}

						// skip the header
						// Source IP,Subnet mask,Source IP info,Destination IP,
						// Subnet Mask,Dest. IP info,Protocol,Service ,Port
						// #,Action
						progressBarValue=0;
						progressBar.setValue(0);
						int maxConnections=10;
						try
						{
							maxConnections= Integer.parseInt(threadCountTextField.getText());
						}
						catch(Exception e)
						{
							addMessageToStatus(Messages.getString("FirewallRuleCheckUI.77")+Messages.getString("FirewallRuleCheckUI.17"));
							threadCountTextField.setText(Messages.getString("FirewallRuleCheckUI.20")); 
							maxConnections=10;
						}
						if(maxConnections>100)
						{
							addMessageToStatus(Messages.getString("FirewallRuleCheckUI.36")+Messages.getString("FirewallRuleCheckUI.42"));
							threadCountTextField.setText(Messages.getString("FirewallRuleCheckUI.78")); 
							maxConnections=10;
						}
						
						ExecutorService executor = Executors.newFixedThreadPool(maxConnections);
						progressBatIncrementPercent = ((double)100 / firewallRuleList.size());
						addMessageToStatus(Messages.getString("FirewallRuleCheckUI.1") + (firewallRuleList.size() - 1) + Messages.getString("FirewallRuleCheckUI.2") + maxConnections + Messages.getString("FirewallRuleCheckUI.4")); //$NON-NLS-3$
						// keep track of results.
						ConcurrentHashMap<String, ResultData> results = new ConcurrentHashMap<String, ResultData>(firewallRuleList.size());
						for (int i = 1; i < firewallRuleList.size(); i++)
						{
							String key = i + Messages.getString("FirewallRuleCheckUI.5"); 
							ResultData res = new ResultData();
							results.put(key, res);
							Runnable worker = new WorkerThread(results, key, firewallRuleList.get(i), username, password);
							executor.execute(worker);
						}// loop through all rules

						executor.shutdown();
						while (!executor.isTerminated())
						{
							Thread.sleep(50);
						}
						System.out.println(Messages.getString("FirewallRuleCheckUI.10")); 
						progressBar.setValue(100);

						// write results to the output file.
						String outputFilename = rulesFile.substring(0, rulesFile.lastIndexOf(Messages.getString("FirewallRuleCheckUI.37"))) + Messages.getString("FirewallRuleCheckUI.38") + sdf.format(new Date()) + Messages.getString("FirewallRuleCheckUI.39"); //$NON-NLS-3$
						PrintWriter fout = new PrintWriter(outputFilename);
						addMessageToStatus(Messages.getString("FirewallRuleCheckUI.40") + outputFilename); 
						int passCount=0;
						for (int i = 0; i < firewallRuleList.size(); i++)
						{
							String key = i + Messages.getString("FirewallRuleCheckUI.11"); 
							StringBuffer outputRow = new StringBuffer();
							// existing columns
							for (int j = 0; j < firewallRuleList.get(i).length; j++)
							{
								outputRow.append(Messages.getString("FirewallRuleCheckUI.79")); 
								outputRow.append(firewallRuleList.get(i)[j]);
								outputRow.append(Messages.getString("FirewallRuleCheckUI.80")); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.41"));// comma 
							}
							// two new columns.
							if (i == 0)
							{
								// header
								SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.81")); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.43") + sdf1.format(new Date())); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.82")); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.41"));// comma 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.83")); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.12")); 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.84")); 

							}
							else
							{

								if (results.get(key).passfail)
								{
									outputRow.append(Messages.getString("FirewallRuleCheckUI.14")); 
									passCount++;
								}
								else
								{
									outputRow.append(Messages.getString("FirewallRuleCheckUI.15")); 
								}
								outputRow.append(Messages.getString("FirewallRuleCheckUI.41"));// comma 
								outputRow.append(Messages.getString("FirewallRuleCheckUI.85")); 
								outputRow.append(results.get(key).failReason);
								outputRow.append(Messages.getString("FirewallRuleCheckUI.86")); 
							}
							fout.println(outputRow);
						}
						fout.flush();
						fout.close();
						endTime=System.currentTimeMillis();
						addMessageToStatus("Pass Count: "+passCount+" out of "+(firewallRuleList.size()-1)+", "+(100*(double)passCount/(firewallRuleList.size()-1))  +"%");
						return 1;
					}

					protected void done()
					{
						addMessageToStatus(Messages.getString("FirewallRuleCheckUI.70")+Messages.getString("FirewallRuleCheckUI.87")+(endTime-startTime)/1000.0+Messages.getString("FirewallRuleCheckUI.88")); //$NON-NLS-3$

					}
				}// inner worker class
				new swingWorker(rulesFile, authFile).execute();

			}
		});
		startButtonPanel.add(btnStartRulesValidation);
		btnStartRulesValidation.setBackground(new Color(250, 128, 114));
		btnStartRulesValidation.setSize(frmSshFirewallValidator.getContentPane().getWidth(), 30);

		JButton button = new JButton(Messages.getString("FirewallRuleCheckUI.72")); 
		button.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				JOptionPane.showMessageDialog(
						frmSshFirewallValidator,
						Messages.getString("FirewallRuleCheckUI.73") + Messages.getString("FirewallRuleCheckUI.74")
								+ Messages.getString("FirewallRuleCheckUI.75"), Messages.getString("FirewallRuleCheckUI.76"),
						JOptionPane.INFORMATION_MESSAGE);
			}
			// source must be in position 3
			// destination hostname must be at pos 6
			// port should be in position 9
		});
		startButtonPanel.add(button);
		
		JLabel threadsLabel = new JLabel(Messages.getString("FirewallRuleCheckUI.lblNewLabel.text")); 
		threadsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		startButtonPanel.add(threadsLabel);
		
		threadCountTextField = new JTextField();
		threadCountTextField.setHorizontalAlignment(SwingConstants.CENTER);
		threadCountTextField.setText(Messages.getString("FirewallRuleCheckUI.textField.text")); 
		startButtonPanel.add(threadCountTextField);
		threadCountTextField.setColumns(2);
		// txtpnSss.setSize(frmSshFirewallValidator.getContentPane().getWidth(),600);
		// frmSshFirewallValidator.pack();
		// txtpnSss.setSize(frmSshFirewallValidator.getContentPane().getWidth(),600);
	}

	public synchronized static void addMessageToStatus(String string)
	{
		resultsTextArea.setText(resultsTextArea.getText() + Messages.getString("FirewallRuleCheckUI.71") + string); 
		resultsTextArea.setCaretPosition(resultsTextArea.getText().length() - 1);

	}
}
